home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 2 / Apprentice-Release2.iso / Tools / MPW / GCC 1.37.1r15 / Machines / out-ns32k.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-03-14  |  14.4 KB  |  576 lines  |  [TEXT/MPS ]

  1. /* Subroutines for assembler code output on the NS32000.
  2.    Copyright (C) 1988 Free Software Foundation, Inc.
  3.  
  4. This file is part of GNU CC.
  5.  
  6. GNU CC is free software; you can redistribute it and/or modify
  7. it under the terms of the GNU General Public License as published by
  8. the Free Software Foundation; either version 1, or (at your option)
  9. any later version.
  10.  
  11. GNU CC is distributed in the hope that it will be useful,
  12. but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. GNU General Public License for more details.
  15.  
  16. You should have received a copy of the GNU General Public License
  17. along with GNU CC; see the file COPYING.  If not, write to
  18. the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. /* Some output-actions in ns32k.md need these.  */
  21. #include <stdio.h>
  22. extern FILE *asm_out_file;
  23.  
  24. #define FP_REG_P(X)  (GET_CODE (X) == REG && REGNO (X) > 7 && REGNO (X) < 16)
  25.  
  26. /* Generate the rtx that comes from an address expression in the md file */
  27. /* The expression to be build is BASE[INDEX:SCALE].  To recognize this,
  28.    scale must be converted from an exponent (from ASHIFT) to a
  29.    muliplier (for MULT). */
  30. rtx
  31. gen_indexed_expr (base, index, scale)
  32.      rtx base, index, scale;
  33. {
  34.   rtx addr;
  35.  
  36.   /* This generates an illegal addressing mode, if BASE is
  37.      fp or sp.  This is handled by PRINT_OPERAND_ADDRESS.  */
  38.   if (GET_CODE (base) != REG && GET_CODE (base) != CONST_INT)
  39.     base = gen_rtx (MEM, SImode, base);
  40.   addr = gen_rtx (MULT, SImode, index,
  41.           gen_rtx (CONST_INT, VOIDmode, 1 << INTVAL (scale)));
  42.   addr = gen_rtx (PLUS, SImode, base, addr);
  43.   return addr;
  44. }
  45.  
  46. /* Return 1 if OP is a valid constant int. These can be modeless
  47.    (void mode), so we do not mess with their modes.
  48.  
  49.    The main use of this function is as a predicate in match_operand
  50.    expressions in the machine description.  */
  51.  
  52. int
  53. const_int (op, mode)
  54.      register rtx op;
  55.      enum machine_mode mode;
  56. {
  57.   return (GET_CODE (op) == CONST_INT);
  58. }
  59.  
  60. /* Return 1 if OP is a valid operand of mode MODE.  This
  61.    predicate rejects operands which do not have a mode
  62.    (such as CONST_INT which are VOIDmode).  */
  63. int
  64. reg_or_mem_operand (op, mode)
  65.      register rtx op;
  66.      enum machine_mode mode;
  67. {
  68.   return (GET_MODE (op) == mode
  69.       && (GET_CODE (op) == REG
  70.           || GET_CODE (op) == SUBREG
  71.           || GET_CODE (op) == MEM));
  72. }
  73.  
  74. /* Return the best assembler insn template
  75.    for moving operands[1] into operands[0] as a fullword.  */
  76.  
  77. static char *
  78. singlemove_string (operands)
  79.      rtx *operands;
  80. {
  81.   if (GET_CODE (operands[1]) == CONST_INT
  82.       && INTVAL (operands[1]) <= 7
  83.       && INTVAL (operands[1]) >= -8)
  84.     return "movqd %1,%0";
  85.   return "movd %1,%0";
  86. }
  87.  
  88. char *
  89. output_move_double (operands)
  90.      rtx *operands;
  91. {
  92.   enum anon1 { REGOP, OFFSOP, POPOP, CNSTOP, RNDOP } optype0, optype1;
  93.   rtx latehalf[2];
  94.  
  95.   /* First classify both operands.  */
  96.  
  97.   if (REG_P (operands[0]))
  98.     optype0 = REGOP;
  99.   else if (offsettable_memref_p (operands[0]))
  100.     optype0 = OFFSOP;
  101.   else if (GET_CODE (XEXP (operands[0], 0)) == PRE_DEC)
  102.     optype0 = POPOP;
  103.   else
  104.     optype0 = RNDOP;
  105.  
  106.   if (REG_P (operands[1]))
  107.     optype1 = REGOP;
  108.   else if (CONSTANT_ADDRESS_P (operands[1])
  109.        || GET_CODE (operands[1]) == CONST_DOUBLE)
  110.     optype1 = CNSTOP;
  111.   else if (offsettable_memref_p (operands[1]))
  112.     optype1 = OFFSOP;
  113.   else if (GET_CODE (XEXP (operands[1], 0)) == PRE_DEC)
  114.     optype1 = POPOP;
  115.   else
  116.     optype1 = RNDOP;
  117.  
  118.   /* Check for the cases that the operand constraints are not
  119.      supposed to allow to happen.  Abort if we get one,
  120.      because generating code for these cases is painful.  */
  121.  
  122.   if (optype0 == RNDOP || optype1 == RNDOP)
  123.     abort ();
  124.  
  125.   /* Ok, we can do one word at a time.
  126.      Normally we do the low-numbered word first,
  127.      but if either operand is autodecrementing then we
  128.      do the high-numbered word first.
  129.  
  130.      In either case, set up in LATEHALF the operands to use
  131.      for the high-numbered word and in some cases alter the
  132.      operands in OPERANDS to be suitable for the low-numbered word.  */
  133.  
  134.   if (optype0 == REGOP)
  135.     latehalf[0] = gen_rtx (REG, SImode, REGNO (operands[0]) + 1);
  136.   else if (optype0 == OFFSOP)
  137.     latehalf[0] = adj_offsettable_operand (operands[0], 4);
  138.   else
  139.     latehalf[0] = operands[0];
  140.  
  141.   if (optype1 == REGOP)
  142.     latehalf[1] = gen_rtx (REG, SImode, REGNO (operands[1]) + 1);
  143.   else if (optype1 == OFFSOP)
  144.     latehalf[1] = adj_offsettable_operand (operands[1], 4);
  145.   else if (optype1 == CNSTOP)
  146.     {
  147.       if (CONSTANT_ADDRESS_P (operands[1]))
  148.     latehalf[1] = const0_rtx;
  149.       else if (GET_CODE (operands[1]) == CONST_DOUBLE)
  150.     {
  151.       latehalf[1] = gen_rtx (CONST_INT, VOIDmode,
  152.                  CONST_DOUBLE_HIGH (operands[1]));
  153.       operands[1] = gen_rtx (CONST_INT, VOIDmode,
  154.                  CONST_DOUBLE_LOW (operands[1]));
  155.     }
  156.     }
  157.   else
  158.     latehalf[1] = operands[1];
  159.  
  160.   /* If one or both operands autodecrementing,
  161.      do the two words, high-numbered first.  */
  162.  
  163.   if (optype0 == POPOP || optype1 == POPOP)
  164.     {
  165.       output_asm_insn (singlemove_string (latehalf), latehalf);
  166.       return singlemove_string (operands);
  167.     }
  168.  
  169.   /* Not autodecrementing.  Do the two words, low-numbered first.  */
  170.  
  171.   output_asm_insn (singlemove_string (operands), operands);
  172.  
  173.   operands[0] = latehalf[0];
  174.   operands[1] = latehalf[1];
  175.   return singlemove_string (operands);
  176. }
  177.  
  178. int
  179. check_reg (oper, reg)
  180.      rtx oper;
  181.      int reg;
  182. {
  183.   register int i;
  184.  
  185.   if (oper == 0)
  186.     return 0;
  187.   switch (GET_CODE(oper))
  188.     {
  189.     case REG:
  190.       return (REGNO(oper) == reg) ? 1 : 0;
  191.     case MEM:
  192.       return check_reg(XEXP(oper, 0), reg);
  193.     case PLUS:
  194.     case MULT:
  195.       return check_reg(XEXP(oper, 0), reg) || check_reg(XEXP(oper, 1), reg);
  196.     }
  197.   return 0;
  198. }
  199.  
  200. /* PRINT_OPERAND_ADDRESS is defined to call this function,
  201.    which is easier to debug than putting all the code in
  202.    a macro definition in tm-ns32k.h .  */
  203.  
  204. /* Nonzero if we have printed a base register.
  205.    If zero, on some systems, it means `(sb)' must be printed.  */
  206. int paren_base_reg_printed = 0;
  207.  
  208. print_operand_address (file, addr)
  209.      register FILE *file;
  210.      register rtx addr;
  211. {
  212.   register rtx reg1, reg2, breg, ireg;
  213.   rtx offset;
  214.   static char scales[] = { 'b', 'w', 'd', 0, 'q', };
  215.  
  216.  retry:
  217.   switch (GET_CODE (addr))
  218.     {
  219.     case MEM:
  220.       addr = XEXP (addr, 0);
  221.       if (GET_CODE (addr) == REG)
  222.     if (REGNO (addr) == STACK_POINTER_REGNUM)
  223.       { fprintf (file, "tos"); break; }
  224.     else
  225.       { fprintf (file, "%s", reg_names[REGNO (addr)]); break; }
  226.       else if (CONSTANT_P (addr))
  227.     { output_addr_const (file, addr); break; }
  228.       else if (GET_CODE (addr) == MULT)
  229.     { fprintf (file, "@0"); ireg = addr; goto print_index; }
  230.       else if (GET_CODE (addr) == MEM)
  231.     {
  232.       addr = XEXP (addr, 0);
  233.       if (GET_CODE (addr) == PLUS)
  234.         {
  235.           offset = XEXP (addr, 1);
  236.           addr = XEXP (addr, 0);
  237.         }
  238.       else
  239.         {
  240.           offset = const0_rtx;
  241.         }
  242.       output_addr_const (file, offset);
  243.       fprintf (file, "(%s)", reg_names[REGNO (addr)]);
  244.       break;
  245.     }
  246.  
  247.       if (GET_CODE (addr) != PLUS)
  248.     abort ();
  249.  
  250.       goto retry;
  251.  
  252.     case REG:
  253.       if (REGNO (addr) == STACK_POINTER_REGNUM)
  254.     fprintf (file, "tos");
  255.       else
  256.     fprintf (file, "0(%s)", reg_names[REGNO (addr)]);
  257.       break;
  258.  
  259.     case PRE_DEC:
  260.     case POST_INC:
  261.       fprintf (file, "tos");
  262.       break;
  263.  
  264.     case MULT:
  265.       fprintf (file, "@0");
  266.       ireg = addr; /* [rX:Y] */
  267.       goto print_index;
  268.       break;
  269.  
  270.     case PLUS:
  271.       reg1 = 0;    reg2 = 0;
  272.       ireg = 0;    breg = 0;
  273.       offset = const0_rtx;
  274.       if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  275.     {
  276.       offset = XEXP (addr, 0);
  277.       addr = XEXP (addr, 1);
  278.     }
  279.       else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  280.     {
  281.       offset = XEXP (addr, 1);
  282.       addr = XEXP (addr, 0);
  283.     }
  284.       if (GET_CODE (addr) != PLUS) ;
  285.       else if (GET_CODE (XEXP (addr, 0)) == MULT)
  286.     {
  287.       reg1 = XEXP (addr, 0);
  288.       addr = XEXP (addr, 1);
  289.     }
  290.       else if (GET_CODE (XEXP (addr, 1)) == MULT)
  291.     {
  292.       reg1 = XEXP (addr, 1);
  293.       addr = XEXP (addr, 0);
  294.     }
  295.       /* The case for memory is somewhat tricky:  to get
  296.      a MEM here, the only RTX formats that could
  297.      get here are either (modulo commutativity)
  298.        (PLUS (PLUS (REG *MEM)) CONST) -or-
  299.        (PLUS (PLUS (CONST REG/MULT)) *MEM)
  300.      We take advantage of that knowledge here.  */
  301.       else if (GET_CODE (XEXP (addr, 0)) == MEM
  302.            || GET_CODE (XEXP (addr, 1)) == MEM)
  303.     {
  304.       rtx temp;
  305.  
  306.       if (GET_CODE (XEXP (addr, 0)) == MEM)
  307.         {
  308.           temp = XEXP (addr, 1);
  309.           addr = XEXP (addr, 0);
  310.         }
  311.       else
  312.         {
  313.           temp = XEXP (addr, 0);
  314.           addr = XEXP (addr, 1);
  315.         }
  316.  
  317.       if (GET_CODE (temp) == REG)
  318.         {
  319.           reg1 = temp;
  320.         }
  321.       else
  322.         {
  323.           if (GET_CODE (temp) != PLUS)
  324.         abort ();
  325.  
  326.           if (GET_CODE (XEXP (temp, 0)) == MULT)
  327.         {
  328.           reg1 = XEXP (temp, 0);
  329.           offset = XEXP (temp, 1);
  330.         }
  331.           if (GET_CODE (XEXP (temp, 1)) == MULT)
  332.         {
  333.           reg1 = XEXP (temp, 1);
  334.           offset = XEXP (temp, 0);
  335.         }
  336.           else
  337.         abort ();
  338.         }
  339.     }
  340.       else if (GET_CODE (XEXP (addr, 0)) == REG
  341.            || GET_CODE (XEXP (addr, 1)) == REG)
  342.     {
  343.       rtx temp;
  344.  
  345.       if (GET_CODE (XEXP (addr, 0)) == REG)
  346.         {
  347.           temp = XEXP (addr, 0);
  348.           addr = XEXP (addr, 1);
  349.         }
  350.       else
  351.         {
  352.           temp = XEXP (addr, 1);
  353.           addr = XEXP (addr, 0);
  354.         }
  355.  
  356.       if (GET_CODE (addr) == REG)
  357.         {
  358.           if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  359.         { reg1 = addr; addr = temp; }
  360.           else
  361.         { reg1 = temp; }
  362.         }
  363.       else if (CONSTANT_P (addr))
  364.         {
  365.           if (GET_CODE (offset) == CONST_INT
  366.           && INTVAL (offset))
  367.         offset = plus_constant (addr, INTVAL (offset));
  368.           addr = temp;
  369.         }
  370.       else if (GET_CODE (addr) != PLUS)
  371.         abort ();
  372.       else
  373.         {
  374.           if (CONSTANT_ADDRESS_P (XEXP (addr, 0)))
  375.         {
  376.           offset = XEXP (addr, 0);
  377.           addr = XEXP (addr, 1);
  378.         }
  379.           else if (CONSTANT_ADDRESS_P (XEXP (addr, 1)))
  380.         {
  381.           offset = XEXP (addr, 1);
  382.           addr = XEXP (addr, 0);
  383.         }
  384.           else abort ();
  385.  
  386.           if (GET_CODE (addr) == REG)
  387.         {
  388.           if (REGNO (temp) >= FRAME_POINTER_REGNUM)
  389.             { reg1 = addr; addr = temp; }
  390.           else
  391.             { reg1 = temp; }
  392.         }
  393.           else
  394.         reg1 = temp;
  395.         }
  396.     }
  397.  
  398.       if (GET_CODE (addr) == REG || GET_CODE (addr) == MULT)
  399.     { if (reg1 == 0) reg1 = addr; else reg2 = addr; addr = 0; }
  400.       if (addr != 0)
  401.     {
  402.       if (CONSTANT_P (addr) && reg1)
  403.         {
  404.           /* OFFSET comes second, to prevent outputting
  405.          operands of the form INT+SYMBOL+INT.
  406.          The Genix assembler dies on them.  */
  407.           output_addr_const (file, addr);
  408.           if (offset != const0_rtx)
  409.         {
  410.           putc ('+', file);
  411.           output_addr_const (file, offset);
  412.         }
  413.           ireg = reg1;
  414.           goto print_index;
  415.         }
  416.       else if (GET_CODE (addr) != MEM)
  417.         abort ();
  418.  
  419.       output_addr_const (file, offset);
  420. #ifndef SEQUENT_ADDRESS_BUG
  421.       putc ('(', file);
  422.       paren_base_reg_printed = 0;
  423.       output_address (addr);
  424. #ifdef SEQUENT_BASE_REGS
  425.       if (!paren_base_reg_printed)
  426.         fprintf (file, "(sb)");
  427. #endif
  428.       putc (')', file);
  429. #else /* SEQUENT_ADDRESS_BUG */
  430.       if ((GET_CODE (offset) == SYMBOL_REF
  431.            || GET_CODE (offset) == CONST)
  432.           && GET_CODE (addr) == REG)
  433.         {
  434.           if (reg1) abort ();
  435.           fprintf (file, "[%s:b]", reg_names[REGNO (addr)]);
  436.         }
  437.       else
  438.         {
  439.           putc ('(', file);
  440.           paren_base_reg_printed = 0;
  441.           output_address (addr);
  442. #ifdef SEQUENT_BASE_REGS
  443.           if (!paren_base_reg_printed)
  444.             fprintf (file, "(sb)");
  445. #endif
  446.           putc (')', file);
  447.         }
  448. #endif /* SEQUENT_ADDRESS_BUG */
  449.       ireg = reg1;
  450.       goto print_index;
  451.     }
  452.       else addr = offset;
  453.       if (reg1 && GET_CODE (reg1) == MULT)
  454.     { breg = reg2; ireg = reg1; }
  455.       else if (reg2 && GET_CODE (reg2) == MULT)
  456.     { breg = reg1; ireg = reg2; }
  457.       else if (reg2 || GET_CODE (addr) == MEM)
  458.     { breg = reg2; ireg = reg1; }
  459.       else
  460.     { breg = reg1; ireg = reg2; }
  461.       if (ireg != 0 && breg == 0 && GET_CODE (addr) == LABEL_REF)
  462.         {
  463.       int scale;
  464.       if (GET_CODE (ireg) == MULT)
  465.         {
  466.           scale = INTVAL (XEXP (ireg, 1)) >> 1;
  467.           ireg = XEXP (ireg, 0);
  468.         }
  469.       else scale = 0;
  470.       output_asm_label (addr);
  471.       fprintf (file, "[%s:%c]",
  472.            reg_names[REGNO (ireg)], scales[scale]);
  473.       break;
  474.     }
  475.       if (ireg && breg && offset == const0_rtx)
  476.     fprintf (file, "0(%s)", reg_names[REGNO (breg)]);
  477.       else
  478.     {
  479.       if (addr != 0)
  480.         {
  481.           if (ireg != 0 && breg == 0
  482.           && GET_CODE (offset) == CONST_INT) putc('@', file);
  483.           output_addr_const (file, offset);
  484.         }
  485.       if (breg != 0)
  486.         {
  487.           if (GET_CODE (breg) != REG) abort ();
  488. #ifndef SEQUENT_ADDRESS_BUG
  489.           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
  490.           paren_base_reg_printed = -1;
  491. #else
  492.           if (GET_CODE (offset) == SYMBOL_REF || GET_CODE (offset) == CONST)
  493.         {
  494.           if (ireg) abort ();
  495.           fprintf (file, "[%s:b]", reg_names[REGNO (breg)]);
  496.         }
  497.           else
  498.         {
  499.           fprintf (file, "(%s)", reg_names[REGNO (breg)]);
  500.           paren_base_reg_printed = -1;
  501.         }
  502. #endif
  503.         }
  504.     }
  505.   print_index:
  506.       if (ireg != 0)
  507.     {
  508.       int scale;
  509.       if (GET_CODE (ireg) == MULT)
  510.         {
  511.           scale = INTVAL (XEXP (ireg, 1)) >> 1;
  512.           ireg = XEXP (ireg, 0);
  513.         }
  514.       else scale = 0;
  515.       if (GET_CODE (ireg) != REG) abort ();
  516.       fprintf (file, "[%s:%c]",
  517.            reg_names[REGNO (ireg)],
  518.            scales[scale]);
  519.     }
  520.       break;
  521.     default:
  522.       output_addr_const (file, addr);
  523.     }
  524. }
  525.  
  526. /* National 32032 shifting is so bad that we can get
  527.    better performance in many common cases by using other
  528.    techniques.  */
  529. char *
  530. output_shift_insn (operands)
  531.      rtx *operands;
  532. {
  533.   if (GET_CODE (operands[2]) == CONST_INT
  534.       && INTVAL (operands[2]) > 0
  535.       && INTVAL (operands[2]) <= 3)
  536.     if (GET_CODE (operands[0]) == REG)
  537.       {
  538.     if (GET_CODE (operands[1]) == REG)
  539.       {
  540.         if (REGNO (operands[0]) == REGNO (operands[1]))
  541.           {
  542.         if (operands[2] == const1_rtx)
  543.           return "addd %0,%0";
  544.         else if (INTVAL (operands[2]) == 2)
  545.           return "addd %0,%0\n\taddd %0,%0";
  546.           }
  547.         if (operands[2] == const1_rtx)
  548.           return "movd %1,%0\n\taddd %0,%0";
  549.  
  550.         operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  551.         return "addr %a1,%0";
  552.       }
  553.     if (operands[2] == const1_rtx)
  554.       return "movd %1,%0\n\taddd %0,%0";
  555.       }
  556.     else if (GET_CODE (operands[1]) == REG)
  557.       {
  558.     operands[1] = gen_indexed_expr (const0_rtx, operands[1], operands[2]);
  559.     return "addr %a1,%0";
  560.       }
  561.     else if (INTVAL (operands[2]) == 1
  562.          && GET_CODE (operands[1]) == MEM
  563.          && rtx_equal_p (operands [0], operands[1]))
  564.       {
  565.     rtx temp = XEXP (operands[1], 0);
  566.  
  567.     if (GET_CODE (temp) == REG
  568.         || (GET_CODE (temp) == PLUS
  569.         && GET_CODE (XEXP (temp, 0)) == REG
  570.         && GET_CODE (XEXP (temp, 1)) == CONST_INT))
  571.       return "addd %0,%0";
  572.       }
  573.     else return "ashd %2,%0";
  574.   return "ashd %2,%0";
  575. }
  576.